﻿namespace NTLib.WPF.Interactions
{
    using Core.Extensions;
    using Core.Log;
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Collections.Specialized;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Markup;

    /// <summary>
    /// Base class used to create a interaction element that contains and interact with a collection of children.
    /// </summary>
    /// <typeparam name="TDependencyObject">The type of the dependency object.</typeparam>
    /// <typeparam name="TInteractionContain">The type of the interaction contain.</typeparam>
    /// <seealso cref="NTLib.WPF.Interactions.BaseInteraction{TDependencyObject}" />
    [ContentProperty(nameof(BaseInteractionContainer<TDependencyObject, TInteractionContain>.Children))]
    public abstract class BaseInteractionContainer<TDependencyObject, TInteractionContain> : BaseInteraction<TDependencyObject>
        where TDependencyObject : DependencyObject
        where TInteractionContain : BaseInteraction<TDependencyObject>
    {
        #region Ctor

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseInteractionContainer{TDependencyObject, TInteractionContain}"/> class.
        /// </summary>
        public BaseInteractionContainer()
        {
            this.Children = new ObservableCollection<TInteractionContain>();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the children.
        /// </summary>
        public ObservableCollection<TInteractionContain> Children
        {
            get { return (ObservableCollection<TInteractionContain>)GetValue(CollectionProperty); }
            set { SetValue(CollectionProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Tiggers.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CollectionProperty =
            DependencyProperty.Register("Children", typeof(ObservableCollection<TInteractionContain>), typeof(BaseInteractionContainer<TDependencyObject, TInteractionContain>), new PropertyMetadata(null, CollectionChanged));

        #endregion

        #region Methods

        /// <summary>
        /// Called when the attached method is called.
        /// </summary>
        /// <param name="obj">The object.</param>
        protected override void OnAttached(DependencyObject obj)
        {
            foreach (var tr in Children)
            {
                tr.Attached(obj);
            }
        }

        /// <summary>
        /// Called when the detached method is called.
        /// </summary>
        protected override void OnDetached()
        {
            foreach (var tr in Children)
            {
                tr.Detached();
            }
        }

        /// <summary>
        /// Collections the changed.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="args">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void CollectionChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            if (args.OldValue != null)
            {
                var collection = (args.OldValue as ObservableCollection<TInteractionContain>);
                collection.CollectionChanged -= (sender as BaseInteractionContainer<TDependencyObject, TInteractionContain>).Collection_CollectionChanged;
            }

            if (args.NewValue != null)
            {
                var collection = (args.NewValue as ObservableCollection<TInteractionContain>);
                collection.CollectionChanged += (sender as BaseInteractionContainer<TDependencyObject, TInteractionContain>).Collection_CollectionChanged;
            }
        }

        /// <summary>
        /// Handles the CollectionChanged event of the Collection control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="NotifyCollectionChangedEventArgs"/> instance containing the event data.</param>
        private void Collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            var action = e.Action;
            if (e.Action == NotifyCollectionChangedAction.Replace)
            {
                Collection_CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, e.OldItems, e.OldStartingIndex));
                Collection_CollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, e.NewItems, e.NewStartingIndex));
                return;
            }
            switch (action)
            {
                case NotifyCollectionChangedAction.Add:
                    for (int i = 0; i < e.NewItems.Count; ++i)
                    {
                        if (this.AttachedObject != null)
                        {
                            var item = (e.NewItems[i] as IInteraction);
                            if (item is BaseInteraction<TDependencyObject>)
                                (item as BaseInteraction<TDependencyObject>)._parent = this;
                            item.Attached(this.AttachedObject);
                        }
                    }
                    break;
                case NotifyCollectionChangedAction.Reset:
                case NotifyCollectionChangedAction.Remove:
                    for (int i = 0; i < e.OldItems.Count; ++i)
                    {
                        if (this.AttachedObject != null)
                        {
                            var item = (e.OldItems[i] as IInteraction);

                            if (item is BaseInteraction<TDependencyObject>)
                                (item as BaseInteraction<TDependencyObject>)._parent = null;
                            item.Detached();
                        }
                    }
                    break;
                default:
                    break;
            }
        }

        #endregion
    }

    /// <summary>
    /// Base class used to create a interaction element that contains and interact with a collection of children.
    /// </summary>
    /// <typeparam name="TInteractionContain">The type of the interaction contain.</typeparam>
    /// <seealso cref="NTLib.WPF.Interactions.BaseInteraction{TDependencyObject}" />
    public class BaseInteractionContainer<TInteractionContain> : BaseInteractionContainer<DependencyObject, TInteractionContain>
        where TInteractionContain : BaseInteraction<DependencyObject>
    {

    }
}
